/*
 *  Copyright (c) 2018, Infineon Technologies AG
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification,are permitted provided that the following conditions are met:
 *
 *  - Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  - Redistributions in binary form must reproduce the above copyright notice,
 *  this list of conditions and the following disclaimer in the documentation
 *  and/or other materials provided with the distribution.
 *  - Neither the name of the copyright holders nor the names of its contributors
 *  may be used to endorse or promote products derived from this software without
 *  specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 *  ARE  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 *  LIABLE  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 *  SUBSTITUTE GOODS OR  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 *  CONTRACT, STRICT LIABILITY,OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 *  To improve the quality of the software, users are encouraged to share
 *  modifications, enhancements or bug fixes with Infineon Technologies AG
 *  dave@infineon.com).
 */
/**
 * \defgroup PWM Pulse Width Modulation
 * Control of peripherals for PWM generation.
 * @{
 */
/**
 * \file    config_pwm.h
 * \author  Manuel Escudero Rodriguez
 * \date    09.05.2018
 * \brief   Pulse Width Modulation
 */
#ifndef __CONFIG_PWM_H_
#define __CONFIG_PWM_H_

#include <XMC4200.h>
#include <xmc_ccu4.h>

#define XMC_CCU8_SLICE_EVENT_INPUT_CONFIG_MASK  (15U)
#define XMC_CCU4_SLICE_EVENT_INPUT_CONFIG_MASK  (15U)

/**
 * \name PWM
 * Frequency is limited to 110kHz if control IRQ execution is linked to each 
 * PWM pulse.
 * @{
 */
/** High resolution comparator used to chop C switch power transfer. */
#define PWM_CSG_C               HRPWM0_CSG0
/** High resolution comparator used to chop D switch power transfer. */
#define PWM_CSG_D               HRPWM0_CSG2
///** High resolution comparator used to chop C switch power transfer. */
//#define PWM_CSG_IO              HRPWM0_CSG1
/** Period of master PWM in timer units. Check value if configuration of PWM is changed. [CCU_clock] */
#define PWM_A_B_PERIOD          (0x31F) //PWM_A_B.period_value
#if PWM_A_B_PERIOD < 0x2D7
	#error "PWM_A_B_PERIOD should be longer than 0x2D7 (110KHz maximum frequency)." 
#endif
/** Half period of master PWM in timer units. Check value if configuration of PWM is changed. [CCU_clock] */
#define PWM_A_B_DUTY            ((PWM_A_B_PERIOD + 1) / 2) //PWM_A_B.compare_value_1 //400
/** Period of slave D. [CCU_clock] */
#define PWM_D_PERIOD			(PWM_A_B_PERIOD - 50) //(PWM_A_B_PERIOD - 11) for the burst scheme to work at best.
/** Delay in PWM chaining A to D through an ERU. [CCU_clock] */
#define PWM_CHAIN_DLY_A_D       (7)
/** Minimum dead time setting allowed for PWM_C and PWM_D. [CCU_clock] */
#define PWM_C_D_CHAIN_DLY       (5)
/** Minimum dead time for the A_B leg. [CCU_clk] */
#define PWM_A_B_MIN_DT			(14)
/** Minimum dead time for the C_D leg. [CCU_clk] */
/* Note: PWM_C_D dead time introduced by the hardware is PWM_C_D_CHAIN_DLY */ 
#define PWM_C_D_MIN_DT			(PWM_A_B_MIN_DT - PWM_C_D_CHAIN_DLY)
/** Minimum delay between the end of the power transfer and the switch ON of the synchronous rectifiers. [CCU_clock] */
#define SYNC_ON_DLY           	(parameters_RAM.synch_ON_dly)
/** Minimum delay between the switch off of the synchronous signal and the start of power transfer. [CCU_clock] */
#define SYNC_OFF_DLY            (parameters_RAM.synch_OFF_dly)
/** Minimum delay between the end of the power transfer and the switch ON of the synchronous rectifiers. [CCU_clock] */
#define SYNC_ON_DCM_DLY         (parameters_RAM.synch_ON_DCM_dly)
/** Maximum allowed period for synchronous rectification timer slices, dt greater for leading leg. [CCU_clock] */
#define SYNC_MAX_PERIOD    		(PWM_A_B_PERIOD + 5)
/** Maximum allowed period for synchronous rectification timer slices, dt greater for leading leg. [CCU_clock] */
#define BOOST_SYNC_STRP_OVRLP   (13)
/** Maximum allowed period for synchronous rectification timer slices, dt greater for leading leg. [CCU_clock] */
#define BOOST_SYNC_MAX_PERIOD   (PWM_A_B_PERIOD - 3)
/** Leg with longer dt times is leading one. */
#define LEAD_CONDITION          (parameters_RAM.dead_time_C_D > parameters_RAM.dead_time_A_B)
/** Leg with longer dt times is lagging one. */
#define LAG_CONDITION           (parameters_RAM.dead_time_A_B > parameters_RAM.dead_time_C_D)
/** Starting current peak blanking value. */
#define MIN_BLK					(parameters_RAM.dead_time_A_B + 35) // Keep high for a nicer startup curve.
/** Preescaling clock of blanking increment. */
#define BLK_INC_PRSCLR			(4)
/** Final current peak blanking value. */
#define CSG_BLK					(100)
/** Maximum reference value generated by the high resolution DACs. [DAC_units] */
#define PWM_PEAK_REF_MAX        (0x3FF)
/** Maximum dead time setting for HRPWM dead time at clock frequency. [HRPWM_clock] */
#define HRPWM_CR_MAX			(82)
/** Minimum reference value generated by the high resolution DACs. [DAC_units] */
#define PWM_PEAK_REF_MIN        (20)
/** Resets trap signal. */
#define TRAP_RST()              {(((XMC_GPIO_PORT_t *) PORT0_BASE)->OMR = (uint32_t) 0x10000UL << 7u); \
                                 PWM_D.ccu8_slice_ptr->TCSET = (uint32_t) 1;}
/** Sets trap signal. */
#define TRAP_SET()              (((XMC_GPIO_PORT_t *) PORT0_BASE)->OMR = (uint32_t) 1U << 7u)
/** Check trap signal state */
#define TRAP_ON                 ((((XMC_GPIO_PORT_t *) PORT0_BASE)->IN >> 7u) & (uint32_t) 1u)
/** Load jump detection by voltage undershoot. Fast reaction of synchronous delay. [ADC_units] */
#define SYNCH_VO_LD_JMP			(40)
/** Load jump detection by change in synchronous delay. Fast reaction in change. [ADC_units] */
#define SYNCH_DLY_LD_JMP		(4)	
/** Synchronous conduction time increment delay. Slows down the increment pace. */
#define SYNCH_ADJST_DLY			(2)
/** Dead time dinamic adjustment. Slows down the increment pace. */
#define DT_ADJST_DLY			(2)
/** Current ratio adjustment preescaler. */
#define ADST_DLY_PRSCLR			(2)
/** Current ratio adjustment preescaler. */
#define ADST_OVRLP_PRSCLR		(7)
/** @} */

/**
 * \name FAN
 * @{
 */
/** Period of fan PWM signal. [CCU_clock] */
#define PWM_FAN_PERIOD          (3199u) //PWM_FAN.period_value
/** @} */

/*---------------------------------------------------------------------------*/
/**
 * \brief       Stops synchronous rectifying
 * \return      None
 */
#ifndef DOXYGEN_SKIP
__attribute__((section(".ram_code")))
#endif
static inline void pwm_sync_stop()
{
    /* If the synchronous rectifier have not been annulled previously. */
    if(PWM_E.ccu4_slice_ptr->CMC & ((uint32_t) CCU4_CC4_CMC_STRTS_Msk))
    {
    	/* Deactivates starting event in E and F slices. */
    	PWM_E.ccu4_slice_ptr->CMC &= ~((uint32_t) CCU4_CC4_CMC_STRTS_Msk);
    	PWM_F.ccu4_slice_ptr->CMC &= ~((uint32_t) CCU4_CC4_CMC_STRTS_Msk);
    }
}
/*---------------------------------------------------------------------------*/
/**
* \brief       Adjust blanking time of the comparators
* \return      None
*/
#ifndef DOXYGEN_SKIP
__attribute__((section(".ram_code")))
#endif
static inline void pwm_blk_set(uint16_t blk)
{
	XMC_HRPWM_CSG_UpdateBlankingValue(PWM_CSG_C, (uint32_t)blk);
	XMC_HRPWM_CSG_UpdateBlankingValue(PWM_CSG_D, (uint32_t)blk);
}
/*---------------------------------------------------------------------------*/
/**
* \brief       Adjust Fan PWM duty
* \return      None
*/
#ifndef DOXYGEN_SKIP
__attribute__((section(".ram_code")))
#endif
inline void fan_duty_set(uint16_t duty)
{
	PWM_FAN.ccu8_slice_ptr->CR1S = (uint16_t) duty;
	PWM_FAN.ccu8_module_ptr->GCSS = PWM_FAN.shadow_txfr_msk;
}
/*---------------------------------------------------------------------------*/
/**
* \brief		Adjust peak current reference value.
* \param ref  	Analog comparator DAC reference value.
* \return     	None
*
* The DAC accepts values between a minimum 0 and a maximum 0xFFF. This sets the references
* of the internal high resolution comparators.
*/
#ifndef DOXYGEN_SKIP
__attribute__((section(".ram_code")))
#endif
static inline void peak_ref_set(uint16_t ref)
{
	XMC_HRPWM_CSG_UpdateDACRefDSV1(PWM_CSG_C, (uint32_t)ref);
	XMC_HRPWM_CSG_UpdateDACRefDSV1(PWM_CSG_D, (uint32_t)ref);
	XMC_HRPWM_EnableComparatorShadowTransfer(HRPWM0, XMC_HRPWM_SHADOW_TX_DAC0 | XMC_HRPWM_SHADOW_TX_DAC2);
}

/*---------------------------------------------------------------------------*/
void pwm_init();
void pwm_start();
void pwm_dt_set();

#endif /* __CONFIG_PWM_H_ */
/** @} */
